import {createError, isELementNode} from './util'
import TransformDom from './TransformDom'

const All = 'all'
const Ver = 'vertical'
const Hor = 'horizontal'

const TriggerTypeMap = {
    'mouse': {
        'down': 'mousedown',
        'move': 'mousemove',
        'up': 'mouseup'
    },
    'touch': {
        'down': 'touchstart',
        'move': 'touchmove',
        'up': 'touchend' 
    }
}

const returnTrue = () => true

const getViewportSize = () => {
    return {
        width:  window.innerWidth || document.documentElement.clientWidth,
        height: window.innerHeight || document.documentElement.clientHeight
    }
}
/**
 * @param{string|element} el 移动的主体，必须是element
 * @param{object} options 配置文件，具体内容看下面
 * @param{object.listenerDom} 事件绑定对象，默认el
 * @param{object.postionX} el初始化x轴坐标
 * @param{object.postionY} el初始化y轴坐标
 * @param{object.boundry} 移动范围
 * @param{object.direction}移动方向，值：all 移动方向不受限；vertical 竖直方向；horizontal 水平方向
 * @param{object.onMove} 元素移动时的回调函数
 * @param{object.onScale} 元素放大缩小时的回调函数
 * @param{object.triggerType} 元素移动监听类型
 */
class ControlledDom{
    constructor(el, options = {}){
        el = typeof el === 'string' ? document.querySelector(el) : el

        if (!isELementNode(el)) throw createError(ControlledDom, 'first param need element')

        this.viewportSize = getViewportSize()
        this.el = el
        this.listenerDom = options.listenerDom || el
        this.postionX = options.positionX || 0
        this.postionY = options.positionY || 0
        this.boundary = Object.assign({}, (options.boundary || {}), {
            top: -this.viewportSize.height / 2,
            left: -this.viewportSize.width / 2,
            bottom: this.viewportSize.height / 2,
            right: this.viewportSize.width / 2
        })
        this.direction = options.direction || All
        this.onMove = options.onMove || returnTrue
        this.onScale = options.onScale || returnTrue
        this.triggerType = TriggerTypeMap[options.triggerType || 'mouse']
    }

    init(){
        this.startX = 0
        this.startY = 0
        this.moveX = 0
        this.moveY = 0
        this.prevS = 1
        this.wx = this.viewportSize.width / 2
        this.wy = this.viewportSize.height / 2
        this.isActive = false

        this.mousedown = this.mousedown.bind(this)
        this.mousemove = this.mousemove.bind(this)
        this.mouseup = this.mouseup.bind(this)
        this.removeListener = this.removeListener.bind(this)
        this.transitionCache = window.getComputedStyle(this.el).getPropertyValue('transition')
        this.el.style.transition = 'none'

        this.tdom = new TransformDom(this.el)

        this.tdom.setTransformOrigin(this.wx + 'px', this.wy + 'px')
        this.listenerDom.addEventListener(this.triggerType.down, this.mousedown, false)
        this.triggerType.down === 'mousedown' && this.listenerDom.addEventListener('mouseleave', this.removeListener, false)

        this.tdom.move(this.postionX, this.postionY)
    }

    setScale(s){
        
        if (this.onScale(s, this.prevS, this.el)){
            this.tdom.scale(s)
            this.prevS = s
        }
    }

    mousedown(event){
        event.preventDefault()
        event.stopPropagation()

        this.isActive = true
        this.startX = event.clientX
        this.startY = event.clientY

        this.listenerDom.addEventListener(this.triggerType.move, this.mousemove, false)
        this.listenerDom.addEventListener(this.triggerType.up, this.mouseup, false)
    }

    mousemove(event){
        let px = this.postionX +event.clientX - this.startX
        let py = this.postionY + event.clientY - this.startY

        if (px < this.boundary.left){
            px = this.boundary.left
        }else if (px > this.boundary.right){
            px = this.boundary.right
        }

        if (py < this.boundary.top){
            py = this.boundary.top
        }else if (py > this.boundary.bottom){
            py = this.boundary.bottom
        }

        if (this.direction === All && this.onMove(px, py, this.el)){
            this.tdom.move(px, py)
            this.tdom.setTransformOrigin((this.wx - px) + 'px', (this.wy - py) + 'px')
            
        }else if (this.direction === Ver && this.onMove(0, py, this.el)){
            this.tdom.moveVertical(py)
            this.tdom.setTransformOrigin(this.wx + 'px', (this.wy - py) + 'px')

        }else if (this.direction === Hor && this.onMove(px, 0, this.el)){
            this.tdom.moveHorizontal(px)
            this.tdom.setTransformOrigin((this.wx - px) + 'px', (this.wy ) + 'px')
        }
    }

    mouseup(){
        this.removeListener()
        this.postionX = this.tdom.positionX
        this.postionY = this.tdom.positionY
    }

    removeListener(){
        this.listenerDom.removeEventListener(this.triggerType.move, this.mousemove, false)
        this.listenerDom.removeEventListener(this.triggerType.up, this.mouseup, false)
        this.isActive = false
        this.el.style.transition = this.transitionCache
    }

}

export default ControlledDom
